varying vec3 normal;
varying vec3 vertex;

const vec4 AMBIENT_BLACK=vec4(0.0,0.0,0.0,1.0);
const vec4 DEFAULT_BLACK=vec4(0.0,0.0,0.0,0.0);

bool light_active(in int i)
{
	bool enabled=true;
	
	if ((gl_LightSource[i].ambient==AMBIENT_BLACK)&&
	    (gl_LightSource[i].diffuse==DEFAULT_BLACK)&&
	    (gl_LightSource[i].specular==DEFAULT_BLACK))
		enabled=false;
		
	return(enabled);
}

float do_light_attenuate(in int i,in float dist)
{
	return(1.0/(gl_LightSource[i].constantAttenuation+
		gl_LightSource[i].linearAttenuation*dist+
		gl_LightSource[i].quadraticAttenuation*dist*dist));
}

void do_directional_light(in int i,in vec3 N,in float shininess,inout vec4 ambient,inout vec4 diffuse,inout vec4 specular)
{
	vec3 L=normalize(gl_LightSource[i].position.xyz);
	
	float nl=dot(N,L);
	
	if (nl>0.0)
	{	
		vec3 H=gl_LightSource[i].halfVector.xyz;
		
		float pf=shininess>0.0?pow(max(dot(N,H),0.0),shininess):0.0;

		diffuse+=gl_FrontLightProduct[i].diffuse*nl;
		specular+=gl_FrontLightProduct[i].specular*pf;
	}
	
	ambient+=gl_LightSource[i].ambient;
}

void do_point_light(in int i,in vec3 N,in vec3 V,in float shininess,
                inout vec4 ambient,inout vec4 diffuse,inout vec4 specular)
{
	vec3 D=gl_LightSource[i].position.xyz-V;
	vec3 L=normalize(D);

	float dist=length(D);
	float attenuation=do_light_attenuate(i,dist);

	float nl=dot(N,L);

	if (nl>0.0)
	{	
		vec3 E=normalize(-V);
		vec3 R=-reflect(L,N);
		
		float pf=shininess>0.0?pow(max(dot(R,E),0.0),shininess):0.0;

		diffuse+=gl_FrontLightProduct[i].diffuse*attenuation*nl;
		specular+=gl_FrontLightProduct[i].specular*attenuation*pf;
	}
	
	ambient+=gl_FrontLightProduct[i].ambient*attenuation;
}

void do_spot_light(in int i,in vec3 N,in vec3 V,in float shininess,
               inout vec4 ambient,inout vec4 diffuse,inout vec4 specular)
{
	vec3 D=gl_LightSource[i].position.xyz-V;
	vec3 L=normalize(D);

	float dist=length(D);
	float attenuation=do_light_attenuate(i,dist);

	float nl=dot(N,L);

	if (nl>0.0)
	{	
		float spotEffect=dot(normalize(gl_LightSource[i].spotDirection),-L);
		
		if (spotEffect>gl_LightSource[i].spotCosCutoff)
		{
			attenuation*=pow(spotEffect,gl_LightSource[i].spotExponent);

			vec3 E=normalize(-V);
			vec3 R=-reflect(L,N);
		
			float pf=shininess>0.0?pow(max(dot(R,E),0.0),shininess):0.0;

			diffuse+=gl_FrontLightProduct[i].diffuse*attenuation*nl;
			specular+=gl_FrontLightProduct[i].specular*attenuation*pf;
		}
	}
	
	ambient+=gl_FrontLightProduct[i].ambient*attenuation;
}

void do_lighting(in int numlights,in vec3 N,in vec3 V,in float shininess,
                       inout vec4 ambient,inout vec4 diffuse,inout vec4 specular)
{
	for (int i=0; i<numlights; i++)
	{
		if (light_active(i))
		{
			if (gl_LightSource[i].position.w==0.0)
				do_directional_light(i,N,shininess,ambient,diffuse,specular);
			else if (gl_LightSource[i].spotCutoff==180.0)
				do_point_light(i,N,V,shininess,ambient,diffuse,specular);
			else
				do_spot_light(i,N,V,shininess,ambient,diffuse,specular);
		}
	}
}

void main()
{
	vec3 n=normalize(normal);
	
	vec4 ambient=vec4(0.0);
	vec4 diffuse=vec4(0.0);
	vec4 specular=vec4(0.0);

	do_lighting(gl_MaxLights,n,vertex,gl_FrontMaterial.shininess,ambient,diffuse,specular);
	
	vec4 color=gl_FrontLightModelProduct.sceneColor+
		(ambient*gl_FrontMaterial.ambient)+
		(diffuse*gl_FrontMaterial.diffuse)+
		(specular*gl_FrontMaterial.specular);
	             
	color=clamp(color,0.0,1.0);
	
	gl_FragColor=color;
}
